import json
import os
import time
from flask import Flask, jsonify, request, Response, send_file, send_from_directory
from werkzeug.serving import WSGIRequestHandler
from flask_cors import CORS
from email.utils import encode_rfc2231
app = Flask(__name__)
CUSTOM_STORAGE = r"E:\下载"
UPLOAD_FOLDER = r"E:\桌面\upload"
CORS(app)  # 允许跨域请求
# 修改默认传输块大小（16KB -> 1MB）
WSGIRequestHandler.max_http_header_size = 1024 * 1024
from urllib.parse import unquote
import sys
from werkzeug.http import quote_header_value

from werkzeug.http import quote_header_value
from urllib.parse import quote
def safe_filename(filename):
    """RFC 5987兼容的编码方法（适配新版Werkzeug）"""
    try:
        # 旧浏览器兼容（去掉 `allow_token=False`）
        return quote(filename, safe='')
    except UnicodeEncodeError:
        return quote(filename.encode('utf-8'), safe='')
def validate_file_path(filename):
    """验证文件路径安全性"""
    safe_dir = os.path.realpath(CUSTOM_STORAGE)
    file_path = os.path.realpath(os.path.join(safe_dir, filename))
    return file_path.startswith(safe_dir)

@app.route('/')
def index():
     return send_from_directory(r'E:\下载\EmailCount', 'largeFile.html')
@app.route('/api/files', methods=['GET'])
def list_files():
    """获取文件列表"""
    try:
        files = []
        for f in os.listdir(CUSTOM_STORAGE):
            file_path = os.path.join(CUSTOM_STORAGE, f)
            if os.path.isfile(file_path):
                stat = os.stat(file_path)
                files.append({
                    'name': f,
                    'size': stat.st_size,
                    'modified': int(stat.st_mtime)
                })
        return jsonify({'code': 200, 'data': files})
    except Exception as e:
        return jsonify({'code': 500, 'error': str(e)})


def generate_chunks(file_path, speed_limit_kb=1024):
    """生成带有速率控制的文件流"""
    chunk_size = 1024 * 512  # 512KB 块大小
    speed_limit = speed_limit_kb * 1024  # 转换为字节/秒

    with open(file_path, 'rb') as f:
        while True:
            start_time = time.time()
            chunk = f.read(chunk_size)
            if not chunk:
                break
            yield chunk

            # 计算速率控制
            elapsed = time.time() - start_time
            expected_time = len(chunk) / speed_limit
            if elapsed < expected_time:
                time.sleep(expected_time - elapsed)


@app.route('/api/download', methods=['GET'])
def download_file():
    """分块下载端点"""
    # 获取并解码文件名
    filename = request.args.get('file')
    #filename = unquote(raw_filename)  # 关键解码



    if not filename or not validate_file_path(filename):
        return jsonify({'code': 403, 'error': 'Invalid file path'})

    file_path = os.path.abspath(os.path.join(CUSTOM_STORAGE, filename))

    if not os.path.isfile(file_path):

        return jsonify({'code': 404, 'error': 'File not found'})

    # 获取速率限制参数（单位：KB/s）
    speed_limit = int(request.args.get('speed', 1024))

    # 创建响应流
    response = Response(
        generate_chunks(file_path, speed_limit),
        mimetype='application/octet-stream',
        direct_passthrough=True
    )

    # 设置响应头
    encoded_name = safe_filename(filename)
    response.headers['Content-Disposition'] = (
        f'attachment; filename="{encoded_name}"; '
        f'filename*=UTF-8\'\'{encoded_name}'  # 确保现代浏览器兼容
    )
    return response

from mimetypes import guess_type
import pandas as pd

from docx import Document  # 添加 python-docx 库

@app.route('/api/preview', methods=['GET'])
def preview_file():
    """通用文件预览接口"""
    filename = request.args.get('file')

    if not filename or not validate_file_path(filename):
        return jsonify({'code': 403, 'error': 'Invalid file path'})

    file_path = os.path.join(CUSTOM_STORAGE, filename)
    print(file_path)
    if not os.path.isfile(file_path):
        return jsonify({'code': 404, 'error': 'File not found'})

    # 获取 MIME 类型（用于识别文件类型）
    mime_type, _ = guess_type(file_path)

    # **1. 文本文件 (txt, csv, json, html)**
    if mime_type and mime_type.startswith('text'):
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
            return jsonify({'code': 200, 'type': 'text', 'data': content})
        except Exception as e:
            return jsonify({'code': 500, 'error': str(e)})

    # **2. Excel 文件 (xlsx, xls)**
    elif filename.lower().endswith(('.xls', '.xlsx')):
        try:
            # 修改后
            df = pd.read_excel(file_path)
            # 将 NaN 转为 None（JSON 合法值）
            clean_data = df.where(pd.notnull(df), None).to_dict(orient='records')
            return jsonify({'code': 200, 'type': 'excel', 'data': clean_data})
        except Exception as e:
            return jsonify({'code': 500, 'error': str(e)})
       #json
    elif filename.lower().endswith(('.json')):
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
                #result = json.loads(content)
            return jsonify({'code': 200, 'type': 'text', 'data': content})
        except Exception as e:
            return jsonify({'code': 500, 'error': str(e)})
    # **3. 图片 / PDF / 其他二进制文件**
    elif mime_type and (mime_type.startswith('image') or mime_type == 'application/pdf'):
        return send_file(file_path, mimetype=mime_type)
    # 4. 处理 Word 文档（.docx）
    elif filename.lower().endswith('.docx'):
        try:
            # 使用 python-docx 提取文本内容
            doc = Document(file_path)
            content = '\n'.join([para.text for para in doc.paragraphs])
            return jsonify({'code': 200, 'type': 'text', 'data': content})
        except Exception as e:
            return jsonify({'code': 500, 'error': f'DOCX文件处理失败: {str(e)}'})

    # **6. 其他未知文件**
    else:
        return jsonify({'code': 400, 'error': 'Unsupported file type'})

@app.route('/upload', methods=['POST'])
def upload_file():
    if 'file' not in request.files:
        return jsonify({'error': 'No file part'})
    file = request.files['file']
    if file.filename == '':
        return jsonify({'error': 'No selected file'})
    filepath = os.path.join(UPLOAD_FOLDER, file.filename)
    file.save(filepath)
    return jsonify({'message': 'File uploaded successfully', 'filename': file.filename})

if __name__ == '__main__':
    # 指定证书和私钥路径
    ssl_context = (r'D:\workspace\python_project\my_first_demo\cert.pem', r'D:\workspace\python_project\my_first_demo\key.pem')
    app.run(
        host='0.0.0.0',
        port=5002,
        threaded=True,
        ssl_context=ssl_context  # 启用 HTTPS
    )